package com.andy.blog.dal.service.impl;

import com.andy.blog.common.constant.UserConstants;
import com.andy.blog.common.core.domain.entity.SysRole;
import com.andy.blog.common.core.domain.entity.SysUser;
import com.andy.blog.common.enums.DeleteTypeEnum;
import com.andy.blog.common.exception.BlogServiceException;
import com.andy.blog.common.reponse.BlogResultCode;
import com.andy.blog.common.utils.DateUtils;
import com.andy.blog.common.utils.SecurityUtils;
import com.andy.blog.common.utils.TransformUtils;
import com.andy.blog.common.utils.bean.BeanValidators;
import com.andy.blog.dal.domain.SysUserDO;
import com.andy.blog.dal.domain.SysUserRoleDO;
import com.andy.blog.dal.mapper.SysRoleMapper;
import com.andy.blog.dal.mapper.SysUserMapper;
import com.andy.blog.dal.mapper.SysUserRoleMapper;
import com.andy.blog.dal.service.SysUserDalService;
import com.andy.blog.dal.vo.SysUserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Created by andy on 2023-04-05 11:38
 */
@Service
public class SysUserDalServiceImpl implements SysUserDalService {
    private static final Logger log = LoggerFactory.getLogger(SysUserDalServiceImpl.class);

    @Resource
    private SysUserMapper userMapper;

    @Resource
    private SysRoleMapper roleMapper;

    @Resource
    private SysUserRoleMapper userRoleMapper;

    @Autowired
    protected Validator validator;

    /**
     * 根据条件分页查询用户列表
     */
    @Override
    public IPage<SysUserDO> selectListByPage(SysUserVO userVO) {
        LambdaQueryWrapper<SysUserDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysUserDO::getIsDeleted, DeleteTypeEnum.DELETE_N.getCode())
                .eq(Objects.nonNull(userVO.getId()), SysUserDO::getId, userVO.getId())
                .like(StringUtils.isNotBlank(userVO.getUserName()), SysUserDO::getUserName, userVO.getUserName())
                .eq(StringUtils.isNotBlank(userVO.getStatus()), SysUserDO::getStatus, userVO.getStatus())
                .like(StringUtils.isNotBlank(userVO.getPhoneNumber()), SysUserDO::getPhoneNumber, userVO.getPhoneNumber())
                .ge(StringUtils.isNotBlank(userVO.getBeginTime()), SysUserDO::getCreateTime, userVO.getBeginTime())
                .le(StringUtils.isNotBlank(userVO.getEndTime()), SysUserDO::getCreateTime, userVO.getEndTime());
        IPage<SysUserDO> page = new Page<>(userVO.getPageNum(), userVO.getPageSize());

        return userMapper.selectPage(page, lambdaQueryWrapper);
    }

    @Override
    public List<SysUserDO> selectUserList(SysUserVO sysUserVO) {
        LambdaQueryWrapper<SysUserDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper
                .eq(SysUserDO::getIsDeleted, DeleteTypeEnum.DELETE_N.getCode())
                .eq(Objects.nonNull(sysUserVO.getId()) && !Objects.equals(sysUserVO.getId(), 0L), SysUserDO::getId, sysUserVO.getId())
                .like(org.apache.commons.lang3.StringUtils.isNotBlank(sysUserVO.getUserName()), SysUserDO::getUserName, sysUserVO.getUserName())
                .eq(org.apache.commons.lang3.StringUtils.isNotBlank(sysUserVO.getStatus()), SysUserDO::getStatus, sysUserVO.getStatus())
                .like(org.apache.commons.lang3.StringUtils.isNotBlank(sysUserVO.getPhoneNumber()), SysUserDO::getPhoneNumber, sysUserVO.getPhoneNumber())
                .ge(org.apache.commons.lang3.StringUtils.isNotBlank(sysUserVO.getBeginTime()), SysUserDO::getCreateTime, sysUserVO.getBeginTime())
                .le(org.apache.commons.lang3.StringUtils.isNotBlank(sysUserVO.getEndTime()), SysUserDO::getCreateTime, sysUserVO.getEndTime());

        return userMapper.selectList(lambdaQueryWrapper);
    }

    /**
     * 根据条件分页查询未分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public List<SysUser> selectUnallocatedList(SysUser user) {
        return userMapper.selectUnallocatedList(user);
    }

    /**
     * 通过用户名查询用户
     *
     * @param userName 用户名
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByUserName(String userName) {
        return userMapper.selectUserByUserName(userName);
    }

    /**
     * 通过用户ID查询用户
     *
     * @param userId 用户ID
     * @return 用户对象信息
     */
    @Override
    public SysUserDO selectUserById(Long userId) {
        return userMapper.selectUserById(userId);
    }

    @Override
    public SysUserDO getById(Long userId) {
        return userMapper.selectById(userId);
    }

    /**
     * 查询用户所属角色组
     *
     * @param userName 用户名
     * @return 结果
     */
    @Override
    public String selectUserRoleGroup(String userName) {
        List<SysRole> list = roleMapper.selectRolesByUserName(userName);
        if (CollectionUtils.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        return list.parallelStream().map(SysRole::getRoleName).collect(Collectors.joining(","));
    }


    /**
     * 校验用户名称是否唯一
     */
    @Override
    public boolean checkUserNameUnique(Long userId, String userName) {
        SysUserDO sysUserDO = buildUniqueWrapper(userName, null, null);
        if (Objects.nonNull(sysUserDO) && !Objects.equals(sysUserDO.getId(), userId)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 构造条件查询
     */
    private SysUserDO buildUniqueWrapper(String userName, String email, String phoneNumber) {
        LambdaQueryWrapper<SysUserDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper
                .eq(org.apache.commons.lang3.StringUtils.isNotBlank(userName), SysUserDO::getUserName, userName)
                .eq(org.apache.commons.lang3.StringUtils.isNotBlank(email), SysUserDO::getEmail, email)
                .eq(org.apache.commons.lang3.StringUtils.isNotBlank(phoneNumber), SysUserDO::getPhoneNumber, phoneNumber)
                .eq(SysUserDO::getIsDeleted, DeleteTypeEnum.DELETE_N.getCode())
                .last("limit 1");
        return userMapper.selectOne(lambdaQueryWrapper);
    }

    /**
     * 校验手机号码是否唯一
     */
    @Override
    public boolean checkPhoneUnique(Long userId, String phoneNumber) {
        SysUserDO sysUserDO = buildUniqueWrapper(null, null, phoneNumber);
        if (Objects.nonNull(sysUserDO) && !Objects.equals(sysUserDO.getId(), userId)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验email是否唯一
     */
    @Override
    public boolean checkEmailUnique(Long userId, String email) {
        SysUserDO sysUserDO = buildUniqueWrapper(null, email, null);
        if (Objects.nonNull(sysUserDO) && !Objects.equals(sysUserDO.getId(), userId)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验用户是否允许操作
     *
     * @param user 用户信息
     */
    @Override
    public void checkUserAllowed(SysUser user) {
        if (Objects.nonNull(user.getId()) && user.isAdmin()) {
            throw new BlogServiceException("不允许操作超级管理员用户");
        }
    }

    /**
     * 新增保存用户信息
     */
    @Override
    public Long insertUser(SysUserVO sysUserVO) {

        SysUserDO sysUserDO = TransformUtils.transform(sysUserVO, SysUserDO.class);

        sysUserDO.setPassword(SecurityUtils.encryptPassword(sysUserVO.getPassword()));
        sysUserDO.setCreateBy(SecurityUtils.getUsername());
        sysUserDO.setCreateTime(DateUtils.getCurrentDate());
        sysUserDO.setIsDeleted(DeleteTypeEnum.DELETE_N.getCode());

        int rows;
        try {
            rows = userMapper.insert(sysUserDO);
        } catch (Exception e) {
            throw new BlogServiceException(BlogResultCode.BLOG_000100, e);
        }

        if (Objects.equals(rows, 0)) {
            throw new BlogServiceException(BlogResultCode.BLOG_000100);
        }

        return sysUserDO.getId();
    }

    /**
     * 注册用户信息
     *
     * @param sysUserVO 用户信息
     * @return 结果
     */
    @Override
    public boolean registerUser(SysUserVO sysUserVO) {
        SysUserDO sysUserDO = TransformUtils.transform(sysUserVO, SysUserDO.class);

        sysUserDO.setCreateBy(sysUserDO.getUserName());
        sysUserDO.setCreateTime(DateUtils.getCurrentDate());
        sysUserDO.setIsDeleted(DeleteTypeEnum.DELETE_N.getCode());

        try {
            return userMapper.insert(sysUserDO) > 0;
        } catch (Exception e) {
            throw new BlogServiceException(BlogResultCode.BLOG_000100, e);
        }
    }

    /**
     * 修改保存用户信息
     */
    @Override
    public void updateUser(SysUserVO sysUserVO) {

        SysUserDO sysUserDO = new SysUserDO();
        sysUserDO.setId(sysUserVO.getId());
        sysUserDO.setUserName(sysUserVO.getUserName());
        sysUserDO.setNickName(sysUserVO.getNickName());
        sysUserDO.setEmail(sysUserVO.getEmail());
        sysUserDO.setPhoneNumber(sysUserVO.getPhoneNumber());
        sysUserDO.setSex(sysUserVO.getSex());
        sysUserDO.setStatus(sysUserVO.getStatus());
        sysUserDO.setRemark(sysUserVO.getRemark());
        sysUserDO.setUpdateBy(SecurityUtils.getUsername());
        sysUserDO.setUpdateTime(DateUtils.getCurrentDate());

        int rows;
        try {
            rows = userMapper.updateById(sysUserDO);
        } catch (Exception e) {
            throw new BlogServiceException(BlogResultCode.BLOG_000100, e);
        }

        if (Objects.equals(rows, 0)) {
            throw new BlogServiceException(BlogResultCode.BLOG_000100);
        }
    }

    /**
     * 用户授权角色
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     */
    @Override
    @Transactional
    public void insertUserAuth(Long userId, Long[] roleIds) {
        userRoleMapper.deleteUserRoleByUserId(userId);
        insertUserRole(userId, roleIds);
    }

    /**
     * 修改用户状态
     */
    @Override
    public void updateUserStatus(SysUserVO sysUserVO) {

        SysUserDO sysUserDO = TransformUtils.transform(sysUserVO, SysUserDO.class);

        sysUserDO.setUpdateTime(DateUtils.getCurrentDate());
        sysUserDO.setUpdateBy(SecurityUtils.getUsername());

        int row;
        try {
            row = userMapper.updateById(sysUserDO);
        } catch (Exception e) {
            throw new BlogServiceException(BlogResultCode.BLOG_000101, e);
        }

        if (Objects.equals(row, 0)) {
            throw new BlogServiceException(BlogResultCode.BLOG_000101);
        }
    }


    @Override
    public void updateUserProfile(SysUserVO sysUserVO) {
        SysUserDO sysUserDO = TransformUtils.transform(sysUserVO, SysUserDO.class);

        int rows;
        try {
            rows = userMapper.updateById(sysUserDO);
        } catch (Exception e) {
            throw new BlogServiceException(BlogResultCode.BLOG_000100, e);
        }

        if (Objects.equals(rows, 0)) {
            throw new BlogServiceException(BlogResultCode.BLOG_000100);
        }
    }

    /**
     * 修改用户头像
     *
     * @param userId 用户名
     * @param avatar 头像地址
     * @return 结果
     */
    @Override
    public boolean updateUserAvatar(Long userId, String avatar) {

        int result;
        try {
            result = userMapper.updateById(SysUserDO.builder().id(userId).avatar(avatar).updateTime(DateUtils.getCurrentDate()).build());
        } catch (Exception e) {
            throw new BlogServiceException(BlogResultCode.BLOG_000101);
        }
        return result > 0;
    }

    /**
     * 重置用户密码
     *
     * @param userId   用户名
     * @param passWord 密码
     * @return 结果
     */
    @Override
    public boolean resetUserPwd(Long userId, String passWord) {
        LambdaUpdateWrapper<SysUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper
                .set(SysUserDO::getPassword, SecurityUtils.encryptPassword(passWord))
                .set(SysUserDO::getUpdateBy, SecurityUtils.getUsername())
                .set(SysUserDO::getUpdateTime, DateUtils.getCurrentDate())
                .eq(SysUserDO::getId, userId);

        int rows;
        try {
            rows = userMapper.update(null, lambdaUpdateWrapper);
        } catch (Exception e) {
            throw new BlogServiceException(BlogResultCode.BLOG_000100, e);
        }

        return rows > 0;
    }

    /**
     * 新增用户角色信息
     *
     * @param user 用户对象
     */
    public void insertUserRole(SysUser user) {
        this.insertUserRole(user.getId(), user.getRoleIds());
    }


    /**
     * 新增用户角色信息
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     */
    public void insertUserRole(Long userId, Long[] roleIds) {
        if (CollectionUtils.isNotEmpty(Arrays.asList(roleIds))) {
            // 新增用户与角色管理
            List<SysUserRoleDO> list = new ArrayList<>(roleIds.length);
            for (Long roleId : roleIds) {
                SysUserRoleDO ur = new SysUserRoleDO();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                list.add(ur);
            }
            userRoleMapper.batchUserRole(list);
        }
    }

    /**
     * 通过用户ID删除用户
     */
    @Override
    public void deleteUserById(Long userId) {

        int row;
        try {
            row = userMapper.updateById(SysUserDO.builder().id(userId).isDeleted(DeleteTypeEnum.DELETE_Y.getCode()).build());
        } catch (Exception e) {
            throw new BlogServiceException(BlogResultCode.BLOG_000102, e);
        }

        if (Objects.equals(row, 0)) {
            throw new BlogServiceException(BlogResultCode.BLOG_000102);
        }
    }

    /**
     * 导入用户数据
     *
     * @param userList        用户数据列表
     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据
     * @param operName        操作用户
     * @return 结果
     */
    @Override
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(userList)) {
            throw new BlogServiceException("导入用户数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        //String password = configService.selectConfigByKey("sys.user.initPassword");
        String password = "123456";
        for (SysUser user : userList) {
            try {
                // 验证是否存在这个用户
                SysUser u = userMapper.selectUserByUserName(user.getUserName());
                if (Objects.isNull(u)) {
                    BeanValidators.validateWithException(validator, user);
                    user.setPassword(SecurityUtils.encryptPassword(password));
                    user.setCreateBy(operName);
                    //this.insertUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
                } else if (isUpdateSupport) {
                    BeanValidators.validateWithException(validator, user);
                    checkUserAllowed(user);
                    user.setUpdateBy(operName);
                    //this.updateUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new BlogServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public SysUserDO selectById(Long userId) {
        return userMapper.selectById(userId);
    }
}
